package concurrency_queue

import (
	"channel/queue"
	"context"
	"errors"
	"sync/atomic"
	"unsafe"
)

type node[T any] struct {
	val  T
	next unsafe.Pointer // *node[T]
}

type link[T any] struct {
	head unsafe.Pointer // *node[T]
	tail unsafe.Pointer // *node[T]
}

type LinkQueue[T any] struct {
	queue *link[T]
}

func (l *LinkQueue[T]) Enqueue(ctx context.Context, t T) error {
	for {
		if ctx.Err() != nil {
			return ctx.Err()
		}
		newNode := &node[T]{val: t}
		newNodePtr := unsafe.Pointer(newNode)
		tail := atomic.LoadPointer(&l.queue.tail)
		tailNode := (*node[T])(tail)
		tailNext := atomic.LoadPointer(&tailNode.next)

		if atomic.CompareAndSwapPointer(&tailNode.next, tailNext, newNodePtr) {
			if atomic.CompareAndSwapPointer(&l.queue.tail, tail, newNodePtr) {
				return nil
			}
		}
	}

	//l.queue.tail.next = &node[T]{val: t}
	//l.queue.tail = l.queue.tail.next
	//return nil
}

func (l *LinkQueue[T]) Dequeue(ctx context.Context) (T, error) {
	for {
		if ctx.Err() != nil {
			var t T
			return t, ctx.Err()
		}
		head := atomic.LoadPointer(&l.queue.head)
		headNode := (*node[T])(head)

		tail := atomic.LoadPointer(&l.queue.tail)
		tailNode := (*node[T])(tail)

		headNext := atomic.LoadPointer(&headNode.next)

		if headNode == tailNode {
			if headNext == nil {
				var t T
				return t, errors.New("队列为空")
			}
			// 队列非空，tail落后，尝试更新tail
			atomic.CompareAndSwapPointer(&l.queue.tail, tail, headNext)
			continue
		}

		if atomic.CompareAndSwapPointer(&l.queue.head, head, headNext) {
			headNextNode := (*node[T])(headNext)
			val := headNextNode.val
			var t T
			headNextNode.val = t
			return val, nil
		}
	}

	//head := l.queue.head
	//l.queue.head = l.queue.head.next
	//return head.(*node[T]).val, nil
}

func NewLinkQueue[T any]() queue.Queue[T] {
	n := &node[T]{}
	return &LinkQueue[T]{
		queue: &link[T]{
			head: unsafe.Pointer(n),
			tail: unsafe.Pointer(n),
		},
	}
}

var _ queue.Queue[int] = (*LinkQueue[int])(nil)
